#  单例模式是指：保证一个类仅有一个实例，并提供一个访问它的全局访问点。

import threading
import time


class Singleton(object):
    def __new__(cls, *args, **kwargs):
        # 检查类 cls 是否具有名为 _instance 的属性，如果没有，说明还没有创建实例
        # _instance 通常用来表示一个类的唯一实例（instance）
        if not hasattr(cls,'_instance'):
            # 生成singleton的父类
            orig = super(Singleton,cls)
            # 创建一个新的实例
            cls._instance= orig.__new__(cls, *args, **kwargs) 

        return cls._instance
    

class Bus(Singleton):
    """
    在 Python 中，threading.RLock() 是一个可重入的锁对象，用于在多线程编程中控制对共享资源的访问。RLock 是可重入锁（Reentrant Lock）的缩写，它允许同一线程在未释放锁的情况下多次获取锁，而普通的 Lock 对象在同一线程中多次调用 acquire() 方法时会导致死锁。

    threading.RLock() 的含义是创建了一个可重入的锁对象，并将其赋值给变量 lock。这个锁对象可以用来在多线程环境中保护临界区，防止多个线程同时访问共享资源而导致数据不一致或竞态条件的问题。
    在使用这个锁对象时，你可以在关键部分的代码中使用 lock.acquire() 来获取锁，并在完成操作后使用 lock.release() 来释放锁，从而确保在同一时刻只有一个线程可以进入被保护的临界区。
    """
    lock = threading.RLock()

    def sendData(self, data):
        self.lock.acquire()
        time.sleep(3)
        print("Sending Signal Data...", data,id(data))
        self.lock.release()



class VisitEntity(threading.Thread):
    """
    定义了一个名为 VisitEntity 的线程类，这个类继承自 threading.Thread 类，因此拥有了线程的相关功能和特性。通过继承 threading.Thread 类，我们可以方便地自定义线程行为，例如定义线程执行的操作、传入线程的参数等。

    一旦定义了这个线程类，我们就可以通过创建 VisitEntity 类的实例来创建并启动新的线程。通常情况下，我们会重写 run 方法来定义线程要执行的操作，然后通过调用 start 方法来启动线程。
    """
    my_bus = ""
    name = ""

    def getName(self):
        return self.name

    def setName(self, name):
        self.name = name

    def run(self):
        self.my_bus = Bus()
        print(self.my_bus) # 三个线程的结果都是一样的
        self.my_bus.sendData(self.name)


if __name__ == "__main__":
    last = None
    for i in range(3):
        print("Entity %d begin to run..." % i)
        my_entity = VisitEntity()
        my_entity.setName("Entity_"+str(i))
        my_entity.start()
"""
优点：
1、由于单例模式要求在全局内只有一个实例，因而可以节省比较多的内存空间;
2、全局只有一个接入点，可以更好地进行数据同步控制，避免多重占用;
3、单例可长驻内存，减少系统开销。

缺点：
1、单例模式的扩展是比较困难的;
2、赋于了单例以太多的职责，某种程度上违反单一职责原则（六大原则后面会讲到）;
3、单例模式是并发协作软件模块中需要最先完成的，因而其不利于测试;
4、单例模式在某种情况下会导致“资源瓶颈”。

应用举例：
1、生成全局惟一的序列号;
2、访问全局复用的惟一资源，如磁盘、总线等;
3、单个对象占用的资源过多，如数据库等;
4、系统全局统一管理，如Windows下的Task Manager;
5、网站计数器。
"""